#include <gtest/gtest.h>
#include "JsonRpcResponse.h"
#include "JsonRpcErrorCode.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>

using namespace RpcError;

/**
 * @brief Test class for JsonRpcResponse
 */
class TestJsonRpcResponse : public ::testing::Test
{
protected:
    void SetUp() override {}
    void TearDown() override {}
};

TEST_F(TestJsonRpcResponse, DefaultConstructor)
{
    JsonRpcResponse response;
    
    // Default constructor should create an invalid response
    EXPECT_FALSE(response.isValid());
    EXPECT_FALSE(response.hasResult());
    EXPECT_TRUE(response.hasError());
    EXPECT_TRUE(response.result().isEmpty());
    EXPECT_TRUE(response.error().isEmpty());
    EXPECT_TRUE(response.id().isNull());
    
    // JSON representation should be minimal
    QJsonObject json = response.toJson();
    EXPECT_EQ(json["jsonrpc"].toString(), "2.0");
    EXPECT_FALSE(json.contains("id"));
    EXPECT_FALSE(json.contains("result"));
    EXPECT_FALSE(json.contains("error"));
}

TEST_F(TestJsonRpcResponse, SetGetResult)
{
    JsonRpcResponse response(QVariant(123));
    
    QJsonObject result1;
    result1["value"] = 42;
    response.setResult(result1);
    EXPECT_TRUE(response.hasResult());
    EXPECT_EQ(response.result()["value"].toInt(), 42);
    
    QJsonObject result2;
    result2["message"] = "test";
    response.setResult(result2);
    EXPECT_EQ(response.result()["message"].toString(), "test");
}

TEST_F(TestJsonRpcResponse, HasResult)
{
    JsonRpcResponse response(QVariant(123));
    EXPECT_FALSE(response.hasResult());
    
    QJsonObject result;
    result["value"] = 123;
    response.setResult(result);
    EXPECT_TRUE(response.hasResult());
    
    response.setResult(QJsonObject());
    EXPECT_FALSE(response.hasResult());
}

TEST_F(TestJsonRpcResponse, ResultTypes)
{
    JsonRpcResponse response(QVariant(123));
    
    // Test integer result
    QJsonObject intResult;
    intResult["value"] = 100;
    response.setResult(intResult);
    EXPECT_EQ(response.result()["value"].toInt(), 100);
    
    // Test string result
    QJsonObject stringResult;
    stringResult["message"] = "hello";
    response.setResult(stringResult);
    EXPECT_EQ(response.result()["message"].toString(), "hello");
    
    // Test boolean result
    QJsonObject boolResult;
    boolResult["flag"] = true;
    response.setResult(boolResult);
    EXPECT_EQ(response.result()["flag"].toBool(), true);
    
    // Test array result
    QJsonObject arrayResult;
    arrayResult["items"] = QJsonArray{1, 2, 3};
    response.setResult(arrayResult);
    EXPECT_TRUE(response.result()["items"].isArray());
}

TEST_F(TestJsonRpcResponse, SetGetError)
{
    JsonRpcResponse response(QVariant(123));
    
    QJsonObject error1;
    error1["code"] = INVALID_REQUEST;
    error1["message"] = QString::fromStdString(Code2Msg(INVALID_REQUEST));
    response.setError(error1);
    
    EXPECT_TRUE(response.hasError());
    EXPECT_EQ(response.error()["code"].toInt(), INVALID_REQUEST);
    EXPECT_EQ(response.error()["message"].toString(), QString::fromStdString(Code2Msg(INVALID_REQUEST)));
    
    QJsonObject error2;
    error2["code"] = PARSE_ERROR;
    error2["message"] = QString::fromStdString(Code2Msg(PARSE_ERROR));
    error2["data"] = "Additional info";
    response.setError(error2);
    
    EXPECT_EQ(response.error()["code"].toInt(), PARSE_ERROR);
    EXPECT_EQ(response.error()["data"].toString(), QString::fromStdString("Additional info"));
}

TEST_F(TestJsonRpcResponse, HasError)
{
    JsonRpcResponse response(QVariant(123));
    EXPECT_TRUE(response.hasError()); // default response is considered an error.
    
    QJsonObject error;
    error["code"] = METHOD_NOT_FOUND;
    error["message"] = QString::fromStdString(Code2Msg(METHOD_NOT_FOUND));
    response.setError(error);
    
    EXPECT_TRUE(response.hasError());
    
    response.setError(QJsonObject());
    EXPECT_TRUE(response.hasError()); // Empty error object is still considered an error
}

TEST_F(TestJsonRpcResponse, ErrorStructure)
{
    JsonRpcResponse response(QVariant(123));
    
    // Test minimal error structure
    QJsonObject minimalError;
    minimalError["code"] = INVALID_REQUEST;
    minimalError["message"] = QString::fromStdString(Code2Msg(INVALID_REQUEST));
    response.setError(minimalError);
    
    EXPECT_TRUE(response.error().contains("code"));
    EXPECT_TRUE(response.error().contains("message"));
    EXPECT_FALSE(response.error().contains("data"));
    
    // Test complete error structure
    QJsonObject completeError;
    completeError["code"] = SERVER_ERROR;
    completeError["message"] = QString::fromStdString(Code2Msg(SERVER_ERROR));
    completeError["data"] = QJsonObject{{"details", "Something went wrong"}};
    response.setError(completeError);
    
    EXPECT_TRUE(response.error().contains("data"));
    EXPECT_EQ(response.error()["data"].toObject()["details"].toString(), "Something went wrong");
}

TEST_F(TestJsonRpcResponse, IsValid)
{
    JsonRpcResponse response(QVariant(123));
    EXPECT_FALSE(response.isValid()); // Default response is invalid

    QJsonObject testResult;
    testResult["value"] = "test";
    response.setResult(testResult);
    EXPECT_TRUE(response.isValid());
    
    QJsonObject error;
    error["code"] = METHOD_NOT_FOUND;
    error["message"] = QString::fromStdString(Code2Msg(METHOD_NOT_FOUND));
    response.setError(error);
    EXPECT_TRUE(response.isValid());
    
    // Test invalid scenario - both result and error present
    response.setResult(testResult);

    response.setError(error);
    EXPECT_TRUE(response.result().isEmpty()); // Set error will make result is set to empty.

    response.setResult(testResult);
    EXPECT_TRUE(response.error().isEmpty()); // Set result will make error is set to empty.
}

TEST_F(TestJsonRpcResponse, ToJsonWithResult)
{
    QJsonObject result;
    result["value"] = 42;
    
    JsonRpcResponse response(QVariant(123));
    response.setResult(result);
    QJsonObject json = response.toJson();
    
    EXPECT_EQ(json["jsonrpc"].toString(), "2.0");
    EXPECT_EQ(json["id"].toInt(), 123);
    EXPECT_EQ(json["result"].toObject()["value"].toInt(), 42);
    EXPECT_FALSE(json.contains("error"));
}

TEST_F(TestJsonRpcResponse, ToJsonWithError)
{
    QJsonObject error;
    error["code"] = METHOD_NOT_FOUND;
    error["message"] = QString::fromStdString(Code2Msg(METHOD_NOT_FOUND));
    
    JsonRpcResponse response(QVariant(456));
    response.setError(error);
    QJsonObject json = response.toJson();
    
    EXPECT_EQ(json["jsonrpc"].toString(), "2.0");
    EXPECT_EQ(json["id"].toInt(), 456);
    EXPECT_FALSE(json.contains("result"));
    EXPECT_TRUE(json.contains("error"));
    
    QJsonObject errorObj = json["error"].toObject();
    EXPECT_EQ(errorObj["code"].toInt(), METHOD_NOT_FOUND);
    EXPECT_EQ(errorObj["message"].toString(), QString::fromStdString(Code2Msg(METHOD_NOT_FOUND)));
}

TEST_F(TestJsonRpcResponse, FromJsonWithResult)
{
    QJsonObject result;
    result["status"] = "success";
    
    QJsonObject json;
    json["jsonrpc"] = "2.0";
    json["id"] = 789;
    json["result"] = result;
    
    bool ok = false;
    JsonRpcResponse response = JsonRpcResponse::fromJson(json, &ok);
    EXPECT_TRUE(ok);
    
    EXPECT_EQ(response.id().toInt(), 789);
    EXPECT_EQ(response.result()["status"].toString(), "success");
    EXPECT_FALSE(response.hasError());
}

TEST_F(TestJsonRpcResponse, FromJsonWithError)
{
    QJsonObject error;
    error["code"] = PARSE_ERROR;
    error["message"] = QString::fromStdString(Code2Msg(PARSE_ERROR));
    
    QJsonObject json;
    json["jsonrpc"] = "2.0";
    json["id"] = "request-123";
    json["error"] = error;
    
    bool ok = false;
    JsonRpcResponse response = JsonRpcResponse::fromJson(json, &ok);
    EXPECT_TRUE(ok);
    
    EXPECT_EQ(response.id().toString(), QString("request-123"));
    EXPECT_FALSE(response.hasResult());
    EXPECT_TRUE(response.hasError());
    EXPECT_EQ(response.error()["code"].toInt(), PARSE_ERROR);
    EXPECT_EQ(response.error()["message"].toString(), QString::fromStdString(Code2Msg(PARSE_ERROR)));
}

TEST_F(TestJsonRpcResponse, JsonRoundTrip)
{
    // Test result round trip
    QJsonObject result;
    result["message"] = "test result";
    
    JsonRpcResponse originalResult(111);
    originalResult.setResult(result);
    QJsonObject json = originalResult.toJson();
    
    bool ok = false;
    JsonRpcResponse parsedResult = JsonRpcResponse::fromJson(json, &ok);
    EXPECT_TRUE(ok);
    
    EXPECT_EQ(parsedResult.id().toInt(), 111);
    EXPECT_EQ(parsedResult.result()["message"].toString(), "test result");
    EXPECT_FALSE(parsedResult.hasError());
    
    // Test error round trip
    QJsonObject error;
    error["code"] = INVALID_REQUEST;
    error["message"] = QString::fromStdString(Code2Msg(INVALID_REQUEST));
    error["data"] = "Additional data";
    
    JsonRpcResponse originalError(222);
    originalError.setError(error);
    json = originalError.toJson();
    
    ok = false;
    JsonRpcResponse parsedError = JsonRpcResponse::fromJson(json, &ok);
    EXPECT_TRUE(ok);
    
    EXPECT_EQ(parsedError.id().toInt(), 222);
    EXPECT_FALSE(parsedError.hasResult());
    EXPECT_TRUE(parsedError.hasError());
    EXPECT_EQ(parsedError.error()["code"].toInt(), INVALID_REQUEST);
    EXPECT_EQ(parsedError.error()["data"].toString(), QString::fromStdString("Additional data"));
}

TEST_F(TestJsonRpcResponse, EmptyResult)
{
    JsonRpcResponse response;
    
    QJsonObject result;
    result["message"] = "";
    response.setResult(result);
    EXPECT_TRUE(response.hasResult());
    EXPECT_EQ(response.result()["message"].toString(), "");
    
    QJsonObject json = response.toJson();
    EXPECT_TRUE(json.contains("result"));
    EXPECT_EQ(json["result"].toObject()["message"].toString(), "");
}

TEST_F(TestJsonRpcResponse, NullResult)
{
    JsonRpcResponse response;
    response.setResult(QJsonObject());
    EXPECT_FALSE(response.hasResult());
    
    QJsonObject json = response.toJson();
    EXPECT_FALSE(json.contains("result"));
}

TEST_F(TestJsonRpcResponse, ComplexResult)
{
    QJsonObject complexResult;
    complexResult["name"] = "test";
    complexResult["value"] = 42;
    complexResult["items"] = QJsonArray{1, 2, 3};
    
    JsonRpcResponse response(333);
    response.setResult(complexResult);
    QJsonObject json = response.toJson();
    
    EXPECT_TRUE(json.contains("result"));
    QJsonObject resultObj = json["result"].toObject();
    EXPECT_EQ(resultObj["name"].toString(), "test");
    EXPECT_EQ(resultObj["value"].toInt(), 42);
    EXPECT_TRUE(resultObj.contains("items"));
}

TEST_F(TestJsonRpcResponse, ComplexError)
{
    QJsonObject complexError;
    complexError["code"] = SERVER_ERROR;
    complexError["message"] = QString::fromStdString(Code2Msg(SERVER_ERROR));
    complexError["data"] = QJsonObject{
        {"timestamp", "2024-01-01T00:00:00Z"},
        {"requestId", "req-123"},
        {"details", QJsonArray{"detail1", "detail2"}}
    };
    
    JsonRpcResponse response(444);
    response.setError(complexError);
    QJsonObject json = response.toJson();
    
    EXPECT_TRUE(json.contains("error"));
    QJsonObject errorObj = json["error"].toObject();
    EXPECT_TRUE(errorObj.contains("data"));
    
    QJsonObject data = errorObj["data"].toObject();
    EXPECT_EQ(data["requestId"].toString(), QString("req-123"));
    EXPECT_TRUE(data["details"].isArray());
}
